/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.restaumanager.dao.impl;

import com.restaumanager.api.IFiltreForm;
import com.restaumanager.dao.IDAO;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

/**
 *
 * @author cyril
 */
public class DAO<T, PK extends java.io.Serializable> implements IDAO<T, PK> {

    @PersistenceContext(unitName = "perfectPU")
    protected EntityManager em;
    protected Class<T> type;
    protected CriteriaBuilder cb;

    public DAO(Class<T> type) {
        this.type = type;
    }

    @Override
    public Class<T> getType() {
        return type;
    }

    protected CriteriaBuilder getCb() {
        if (this.cb != null) {
            return this.cb;
        }
        this.cb = em.getCriteriaBuilder();
        return this.cb;
    }

    /**
     * Voir {@link IDAO#ajouter(java.lang.Object) }
     *
     */
    @Override
    public T ajouter(T t) {
        em.persist(t);
        return t;
    }

    /**
     * Voir {@link IDAO#modifier(java.lang.Object) }
     *
     */
    @Override
    public T modifier(T t) {
        return em.merge(t);
    }

    /**
     * Voir {@link IDAO#supprimer(java.io.Serializable) () }
     *
     */
    @Override
    public boolean supprimer(PK k) {
        T t = em.find(type, k);
        if (t == null) {
            return false;
        }
        em.remove(t);
        return true;
    }

    /**
     * Voir {@link IDAO#selectionner(java.io.Serializable) }
     *
     */
    @Override
    public T selectionner(PK k) {
        if (k == null) {
            return null;
        } else {
            return (T) em.find(this.type, k);
        }

    }

    /**
     * Voir {@link IDAO#lister() }
     *
     */
    @Override
    public List<T> lister() {
        CriteriaQuery<T> c = getCb().createQuery(type);
        Root<T> t = c.from(type);

        c.select(t);
        TypedQuery<T> q = em.createQuery(c);

        return (List<T>) q.getResultList();
    }

    /**
     * Voir {@link IDAO#lister(java.lang.String, boolean) }
     *
     */
    @Override
    public List<T> lister(String tri, boolean asc) {
        String ascc = ((asc) ? "ASC" : "DESC");
        String jpql = "SELECT t FROM " + this.type.getSimpleName()
                + " t order by " + tri + " " + ascc;
        Query q = em.createQuery(jpql);

        return (List<T>) q.getResultList();

    }

    /**
     * Voir {@link IDAO#lister(java.lang.String, boolean) }
     *
     */
    public List<T> lister(String attribut, String valeur, int debut, int nombre, String tri, boolean asc) {
        return (List<T>) em.createQuery("SELECT t FROM " + type.getSimpleName()
                + " t where t." + attribut + " = " + valeur
                + " ORDER BY t." + tri
                + ((asc) ? " ASC" : " DESC")).setFirstResult(debut).setMaxResults(nombre).getResultList();

    }

    /**
     * Voir {@link IDAO#supprimer(T t) }
     *
     */
    @Override
    public void supprimer(T t) {
        em.remove(t);
    }

    /**
     * Voir {@link IDAO#supprimer() }
     *
     */
    @Override
    public void supprimer() {
        executerModif("DELETE FROM " + type.getSimpleName());
    }

    /**
     * Voir {@link IDAO#nombreEnreg() }
     *
     */
    @Override
    public Long nombreEnreg() {
        CriteriaQuery<Long> c = getCb().createQuery(Long.class);

        Root<T> t = c.from(type);
        c.select(cb.count(t));

        TypedQuery<Long> q = em.createQuery(c);

        return (Long) q.getSingleResult();
    }

    @Override
    public Long nombreEnreg(IFiltreForm q) {
        List<T> liste = executerRequete(q, null, null);

        return (Long) Long.valueOf(liste.size());
    }

    /**
     * Voir {@link IDAO#lister(int, int, java.lang.String, boolean) () }
     *
     */
    @Override
    public List<T> lister(int debut, int nombre, String tri, boolean asc) {
        return (List<T>) em.createQuery("SELECT t FROM " + type.getSimpleName()
                + " t ORDER BY t." + tri
                + ((asc) ? " ASC" : " DESC")).setFirstResult(debut).setMaxResults(nombre).getResultList();
    }

    @Override
    public List<T> lister(int debut, int nombre, IFiltreForm filtre) {
        Query q = filtre.query(em, null, null);
        q.setFirstResult(debut);
        q.setMaxResults(nombre);
        return (List<T>) q.getResultList();
    }

    /**
     * Voir {@link IDAO#executerRequete(javax.persistence.Query) }
     *
     */
    @Override
    public List<T> executerRequete(String requete, String sortAttrib, String sortDir) {
        return (List<T>) this.executerRequete(em.createQuery(requete));
    }

    @Override
    public List<T> executerRequete(Query requete) {
        return (List<T>) requete.getResultList();
    }

    @Override
    public List<T> executerRequete(IFiltreForm filtreForm, String sortAttrib, String sortDir) {
        return executerRequete(filtreForm.query(em, sortAttrib, sortDir));
    }

    /**
     * Voir {@link IDAO#executerModif(javax.persistence.Query) }
     *
     */
    @Override
    public int executerModif(String requete) {
        return this.executerModif(em.createQuery(requete));
    }

    @Override
    public int executerModif(Query requete) {
        return requete.executeUpdate();
    }

    @Override
    public Query creerQuery(String requete) {
        return em.createQuery(requete);
    }

    @Override
    public List<T> lister(int debut, int nombre, String tri, boolean asc, IFiltreForm filtre) {
        Query q = filtre.query(em, tri, ((asc) ? "ASC" : "DESC"));
        q.setFirstResult(debut);
        q.setMaxResults(nombre);
        return (List<T>) q.getResultList();
    }
}
